package com.dh.convert.rule.function;

import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorJavaType;
import com.googlecode.aviator.runtime.type.AviatorObject;
import com.googlecode.aviator.runtime.type.AviatorRuntimeJavaType;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.EnumSet;
import java.util.Map;
import java.util.Objects;

/**
 * @author huwenxuan
 * @date 2018/11/8
 */
public class EnumFunction extends AbstractFunction {

    private static Map ENUM_CACHE = Maps.newConcurrentMap();

    @Override
    public String getName() {
        return "enum";
    }

    /**
     * 枚举转换
     *
     * @param env
     * @param arg1 数据
     * @param arg2 目标枚举
     * @param arg3 源字段
     * @param arg4 目标字段
     * @return
     */
    @Override
    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4) {
        Object o = arg1.getValue(env);
        Object result = null;

        String className = getField(arg2, env);
        String srcField = getField(arg3, env);
        String targetField = getField(arg4, env);

        if(Objects.isNull(o) || StringUtils.isAnyBlank(className, srcField, targetField)){
            throw new RuntimeException("请检查枚举配置是否正确！");
        }

        String cacheName = Joiner.on("-").join(className, srcField, o);

        try {
            if (null == (result = ENUM_CACHE.get(cacheName))) {
                Class enumClazz;
                try {
                    enumClazz = Class.forName(className);
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(String.format("无法识别类型:%s", className), e);
                }

                EnumSet enumSet = EnumSet.allOf(enumClazz);
                for (Object enum0 : enumSet) {
                    Field sf = enum0.getClass().getDeclaredField(srcField);
                    if (null != sf) {
                        sf.setAccessible(true);
                        if (String.valueOf(o).equals(String.valueOf(sf.get(enum0)))) {
                            Field tf = enum0.getClass().getDeclaredField(targetField);
                            if (null != tf) {
                                tf.setAccessible(true);
                                result = tf.get(enum0);
                                ENUM_CACHE.put(cacheName, result);
                                break;
                            }
                        }
                    }

                }
            }
        } catch (Exception e) {
            throw new RuntimeException(String.format("格转枚举转换%s异常！%s", cacheName,  e.getMessage()));
        }

        if(null == result){
            throw new IllegalArgumentException(String.format("参数%s不在枚举域内", getField(arg1, env)));
        }

        return new AviatorRuntimeJavaType(result);
    }

    /**
     * 根据aviatorObject获取目标字符串
     *
     * @param aviatorObject
     * @param env
     * @return
     */
    private String getField(AviatorObject aviatorObject, Map<String, Object> env) {
        String targetField;
        if (aviatorObject instanceof AviatorJavaType) {
            targetField = ((AviatorJavaType) aviatorObject).getName();
        } else {
            targetField = FunctionUtils.getStringValue(aviatorObject, env);
        }

        return targetField;
    }
}
